package consul

import (
	"fmt"
	"net"

	"gitee.com/zawei/yggdrasil/pkg"
	"gitee.com/zawei/yggdrasil/pkg/config"
	"gitee.com/zawei/yggdrasil/pkg/config/encoder"
	"gitee.com/zawei/yggdrasil/pkg/config/encoder/hcl"
	"gitee.com/zawei/yggdrasil/pkg/config/encoder/json"
	"gitee.com/zawei/yggdrasil/pkg/config/encoder/toml"
	"gitee.com/zawei/yggdrasil/pkg/config/encoder/xml"
	"gitee.com/zawei/yggdrasil/pkg/config/encoder/yaml"
	"gitee.com/zawei/yggdrasil/pkg/config/source"
	"github.com/hashicorp/consul/api"
)

type consulConfig struct {
	Items []struct {
		Prefix      string
		StripPrefix string
		Format      string
	}
	Api *api.Config
}

func init() {
	consulCfg := &consulConfig{}
	if err := config.Get("config", "consul").Scan(consulCfg); err != nil {
		panic(err)
	}

	cfg := api.DefaultConfig()
	if consulCfg.Api != nil {
		if consulCfg.Api.Address != "" {
			addr, port, err := net.SplitHostPort(consulCfg.Api.Address)
			if ae, ok := err.(*net.AddrError); ok && ae.Err == "missing port in address" {
				port = "8500"
				addr = consulCfg.Api.Address
				cfg.Address = fmt.Sprintf("%s:%s", addr, port)
			} else if err == nil {
				cfg.Address = fmt.Sprintf("%s:%s", addr, port)
			}
		}
		if consulCfg.Api.Datacenter != "" {
			cfg.Datacenter = consulCfg.Api.Datacenter
		}
		if consulCfg.Api.Token != "" {
			cfg.Token = consulCfg.Api.Token
		}
	}

	client, err := api.NewClient(cfg)
	if err != nil {
		panic(err)
	}
	sources := make([]source.Source, 0, len(consulCfg.Items))
	encoderMap := make(map[string]encoder.Encoder)
	for _, item := range consulCfg.Items {
		if item.Prefix == "" {
			item.Prefix = pkg.FrameworkName() + "/conf"
		}
		if item.Format == "" {
			item.Format = "json"
		}
		e, ok := encoderMap[item.Format]
		if !ok {
			switch item.Format {
			case "json":
				e = json.NewEncoder()
			case "yaml":
				e = yaml.NewEncoder()
			case "hcl":
				e = hcl.NewEncoder()
			case "xml":
				e = xml.NewEncoder()
			case "toml":
				e = toml.NewEncoder()
			default:
				item.Format = "json"
				if e, ok = encoderMap[item.Format]; !ok {
					e = json.NewEncoder()
				}
			}
		}
		sources = append(sources, &consul{
			addr:        cfg.Address,
			prefix:      item.Prefix,
			stripPrefix: item.StripPrefix,
			encoder:     e,
			client:      client,
		})
	}
	if err := config.Load(sources...); err != nil {
		panic(err)
	}
}
